package com.baidu.sggc.core.common.utils;

import com.baidu.sggc.entity.AuditLog;
import com.baidu.sggc.entity.AuditQueryLog;
import com.baidu.sggc.entity.OperateType;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;

@Component
@Slf4j
public class AuditDescUtil {

    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
    private static final java.time.format.DateTimeFormatter FORMATTER =
            java.time.format.DateTimeFormatter.ofPattern("yyyy年MM月dd日HH时mm分ss秒");

    /**
     * 生成 desc 字符串入口方法
     */
    public static String buildDesc(AuditLog auditLog) {
        // 根据英文操作名获取枚举值
        OperateType operateType = OperateType.getByEnName(auditLog.getOperation());
        if (operateType == null) {
            return "";
        }

        JsonNode extendData = parseExtendData(auditLog.getExtendData());
        log.info("extendData: {}", extendData);
        String userName = auditLog.getUserName();
        String ip = auditLog.getAccessAddress();
        String operateTime = formatOperateTime(auditLog.getOperateTime(), auditLog.getAppName());
        String domain = auditLog.getMenuPath();
        boolean isSuccess = isSuccess(auditLog.getOperateState());

        // 使用完整的枚举名称进行匹配
        switch (operateType) {
            case LIST_QUERY:
            case DETAILS_QUERY:
                return buildQueryDesc(userName, ip, operateTime, domain, extendData, isSuccess);
            case CREATE:
            case COPY:
            case IMPORT:
            case EXPORT:
                return buildCreateDesc(userName, ip, operateTime, domain, extendData, isSuccess, operateType.getZhName());
            case UPDATE:
                return buildUpdateDesc(userName, ip, operateTime, domain, extendData, isSuccess);
            case DELETE:
            case DISABLE:
            case ENABLE:
            case TERMINATE:
            case STOP:
            case CANCEL:
            case END:
                return buildDeleteDesc(userName, ip, operateTime, domain, extendData, isSuccess, operateType.getZhName());
            case UPLOAD:
                return buildUploadDesc(userName, ip, operateTime, domain, extendData, isSuccess);
            case DOWNLOAD:
                return buildDownloadDesc(userName, ip, operateTime, domain, extendData, isSuccess);
            case ILLEGAL_ACCESS:
                return buildSysDesc(userName, ip, operateTime, operateType.getZhName(), isSuccess);
            default:
                return buildGenericDesc(userName, ip, operateTime, domain, operateType.getZhName(), isSuccess);
        }
    }

    /**
     * 生成 QueryLog Desc
     */

    public static String buildQueryDesc(AuditQueryLog auditLog) {
        // 根据英文操作名获取枚举值
        OperateType operateType = OperateType.getByEnName(auditLog.getOperation());
        if (operateType == null) {
            return "";
        }
        JsonNode extendData = parseExtendData(auditLog.getExtendData());
        log.info("extendData: {}", extendData);
        String userName = auditLog.getUserName();
        String ip = auditLog.getAccessAddress();
        String operateTime = formatOperateTime(auditLog.getOperateTime());
        String domain = auditLog.getMenuPath();
        boolean isSuccess = isSuccess(auditLog.getOperateState());

        // 使用完整的枚举名称进行匹配
        switch (operateType) {
            case LIST_QUERY:
            case DETAILS_QUERY:
                return buildQueryDesc(userName, ip, operateTime, domain, extendData, isSuccess);
            default:
                return buildGenericDesc(userName, ip, operateTime, domain, operateType.getZhName(), isSuccess);
        }
    }

    private static String buildSysDesc(String userName, String ip, String operateTime, String operation, boolean isSuccess) {
        return String.format("用户[%s]在机器(IP=%s)于%s执行了%s操作，执行结果%s。",
                userName, ip, operateTime, operation, isSuccess ? "成功" : "失败");
    }

    // === 特殊格式的操作描述构建方法 ===

    private static String buildQueryDesc(String userName, String ip, String operateTime, String domain,
                                         JsonNode extendData, boolean isSuccess) {
        log.info("extendData: {}", extendData);

        StringBuilder queryCriteriaDesc = new StringBuilder("无");
        if (extendData != null && extendData.has("query_criteria")) {
            JsonNode queryCriteria = extendData.get("query_criteria");

            // 查询条件部分
            if (queryCriteria.has("查询条件")) {
                JsonNode conditionNode = queryCriteria.get("查询条件");
                // 详情：唯一标识
                if (conditionNode.has("唯一标识")) {
                    queryCriteriaDesc = new StringBuilder("唯一标识为")
                            .append(conditionNode.get("唯一标识").asText());
                } else {
                    // 多条件
                    String condStr = buildQueryCriteriaDesc(conditionNode);
                    if (!condStr.isEmpty()) {
                        queryCriteriaDesc = new StringBuilder(condStr);
                    }
                }
            }

            // 排序部分
            if (queryCriteria.has("排序")) {
                String sortStr = buildQueryCriteriaDesc(queryCriteria.get("排序"));
                if (!sortStr.isEmpty()) {
                    queryCriteriaDesc.append("，排序：").append(sortStr);
                }
            }

            // 时间范围部分
            if (queryCriteria.has("时间范围")) {
                String timeStr = buildQueryCriteriaDesc(queryCriteria.get("时间范围"));
                if (!timeStr.isEmpty()) {
                    queryCriteriaDesc.append("，时间范围：").append(timeStr);
                }
            }
        }

        log.info("queryCriteriaDesc: {}", queryCriteriaDesc);

        return String.format(
                "用户[%s]在机器(IP=%s)于%s通过[%s]执行了查询操作，查询条件是：%s，执行结果%s。",
                userName, ip, operateTime, domain, queryCriteriaDesc, isSuccess ? "成功" : "失败"
        );
    }


    private static String buildQueryCriteriaDesc(JsonNode criteriaNode) {
        if (criteriaNode == null || !criteriaNode.isObject()) {
            return "无";
        }

        StringBuilder sb = new StringBuilder();
        criteriaNode.fields().forEachRemaining(entry -> {
            String key = entry.getKey();
            JsonNode value = entry.getValue();
            String valueStr = value != null ? value.asText() : "";
            if (!valueStr.isEmpty()) {  // 只拼有值的
                sb.append(key).append("为").append(valueStr).append("，");
            }
        });

        if (sb.length() > 0 && sb.charAt(sb.length() - 1) == '，') {
            sb.setLength(sb.length() - 1);
        }

        // 如果全是空，返回“无”
        return sb.length() > 0 ? sb.toString() : "无";
    }


    /**
     * 新增/复制/导入/导出操作描述
     */
    private static String buildCreateDesc(String userName, String ip, String operateTime, String domain,
                                          JsonNode extendData, boolean isSuccess, String operation) {
        String dataType = getStringValue(extendData, "data_type", "数据");
        String uniqueId = extendData.get("unique_identification").toString();
        int operationNum = getIntValue(extendData, "operation_num", 1);

        return String.format("用户[%s]在机器(IP=%s)于%s通过[%s]执行了%s操作，增加了%s唯一性标识等于[%s]的数据，操作数量[%d]，执行结果%s。",
                userName, ip, operateTime, domain, operation, dataType, uniqueId, operationNum, isSuccess ? "成功" : "失败");
    }

    /**
     * 更新操作描述（适配 GeneralMessage 结构，支持多属性修改）
     */
    private static String buildUpdateDesc(String userName, String ip, String operateTime, String domain,
                                          JsonNode extendData, boolean isSuccess) {
        // 数据类型
        String dataType = getStringValue(extendData, "data_type", "数据类型未知");
        // 数据名称
        String dataName = getStringValue(extendData, "data_name", "数据");
        // 操作数量
        int operationNum = extendData.has("operation_num") ? extendData.get("operation_num").asInt() : 0;

        // 唯一标识（数组转成逗号分隔字符串）
        String uniqueIdStr = "无";
        if (extendData.has("unique_identification") && extendData.get("unique_identification").isArray()) {
            List<String> ids = new ArrayList<>();
            for (JsonNode idNode : extendData.get("unique_identification")) {
                ids.add(idNode.asText());
            }
            uniqueIdStr = String.join(",", ids);
        }

        // 修改的属性（Map 转成 key=value 形式）
        String attributeChanges = "";
        if (extendData.has("attribute_name") && extendData.get("attribute_name").isObject()) {
            List<String> changes = new ArrayList<>();
            Iterator<Map.Entry<String, JsonNode>> fields = extendData.get("attribute_name").fields();
            while (fields.hasNext()) {
                Map.Entry<String, JsonNode> entry = fields.next();
                changes.add(entry.getKey() + "=" + entry.getValue().asText());
            }
            attributeChanges = String.join("，", changes);
        }

        if (attributeChanges.isEmpty()) {
            return String.format(
                    "用户[%s]在机器(IP=%s)于%s通过[%s]执行了修改操作，修改了%d条类型为[%s]、唯一标识为[%s]、名称[%s]的数据，未进行任何属性修改，执行结果%s。",
                    userName, ip, operateTime, domain, operationNum, dataType, uniqueIdStr, dataName,
                    isSuccess ? "成功" : "失败"
            );
        } else {
            return String.format(
                    "用户[%s]在机器(IP=%s)于%s通过[%s]执行了修改操作，修改了%d条类型为[%s]、唯一标识为[%s]、名称[%s]的数据，修改的属性及新值：%s，执行结果%s。",
                    userName, ip, operateTime, domain, operationNum, dataType, uniqueIdStr, dataName,
                    attributeChanges, isSuccess ? "成功" : "失败"
            );
        }
    }

    /**
     * 删除/停用/启用等操作描述
     */
    private static String buildDeleteDesc(String userName, String ip, String operateTime, String domain,
                                          JsonNode extendData, boolean isSuccess, String operation) {
        String uniqueId = extendData.get("unique_identification") != null ?
                extendData.get("unique_identification").toString() : "无";
        int operationNum = getIntValue(extendData, "operation_num", 1);

        return String.format("用户[%s]在机器(IP=%s)于%s通过[%s]执行了%s操作，操作了唯一性标识等于[%s]的数据，操作数量[%d]，执行结果%s。",
                userName, ip, operateTime, domain, operation, uniqueId, operationNum, isSuccess ? "成功" : "失败");
    }

    /**
     * 上传操作描述
     */
    private static String buildUploadDesc(String userName, String ip, String operateTime, String domain,
                                          JsonNode extendData, boolean isSuccess) {
        FileInfo fileInfo = parseFileInfo(extendData);
        String filesStr = fileInfo.fileNames.isEmpty() ? "无文件" :
                fileInfo.fileNames.stream().map(f -> "文件名：" + f).collect(Collectors.joining("，"));

        return String.format("用户[%s]在机器(IP=%s)于%s通过[%s]执行了上传操作，上传了[%s]的文件到目录[%s]，执行结果%s。",
                userName, ip, operateTime, domain, filesStr, fileInfo.directory, isSuccess ? "成功" : "失败");
    }

    /**
     * 下载操作描述
     */
    private static String buildDownloadDesc(String userName, String ip, String operateTime, String domain,
                                            JsonNode extendData, boolean isSuccess) {
        FileInfo fileInfo = parseFileInfo(extendData);
        String filesStr = fileInfo.fileNames.isEmpty() ? "无文件" :
                fileInfo.fileNames.stream().map(f -> "文件名：" + f).collect(Collectors.joining("，"));

        return String.format("用户[%s]在机器(IP=%s)于%s通过[%s]执行了下载操作，从目录[%s]下载了[%s]的文件，执行结果%s。",
                userName, ip, operateTime, domain, fileInfo.directory, filesStr, isSuccess ? "成功" : "失败");
    }

    // === 通用方法 ===

    /**
     * 通用操作描述
     */
    private static String buildGenericDesc(String userName, String ip, String operateTime, String domain,
                                           String operation, boolean isSuccess) {
        return String.format("用户[%s]在机器(IP=%s)于%s通过[%s]执行了%s操作，执行结果%s。",
                userName, ip, operateTime, domain, operation, isSuccess ? "成功" : "失败");
    }

    // === 辅助方法 ===

    private static JsonNode parseExtendData(String extendDataJson) {
        try {
            return OBJECT_MAPPER.readTree(extendDataJson);
        } catch (Exception e) {
            return null;
        }
    }

    private static String formatOperateTime(LocalDateTime localDateTime) {
        return localDateTime != null ? localDateTime.format(FORMATTER) : "";
    }

    private static String formatOperateTime(LocalDateTime localDateTime, String appName) {
        if (localDateTime == null) {
            return "";
        }

        // 如果不是"custom-portal"，则加8小时（GMT转北京时间）
        if (!"custom-portal".equalsIgnoreCase(appName)) {
            localDateTime = localDateTime.plusHours(8);
        }

        return localDateTime.format(FORMATTER);
    }


    private static String getStringValue(JsonNode node, String fieldName, String defaultValue) {
        return (node != null && node.has(fieldName)) ? node.get(fieldName).asText() : defaultValue;
    }

    private static int getIntValue(JsonNode node, String fieldName, int defaultValue) {
        return (node != null && node.has(fieldName)) ? node.get(fieldName).asInt() : defaultValue;
    }

    private static FileInfo parseFileInfo(JsonNode extendData) {
        FileInfo fileInfo = new FileInfo();
        if (extendData == null) {
            return fileInfo;
        }

        JsonNode fileInfoNode = extendData.get("file_info");
        if (fileInfoNode == null || !fileInfoNode.isObject()) {
            return fileInfo;
        }

        Iterator<String> fieldNames = fileInfoNode.fieldNames();
        if (fieldNames.hasNext()) {
            fileInfo.directory = fieldNames.next();
            JsonNode files = fileInfoNode.get(fileInfo.directory);
            if (files != null && files.isArray()) {
                fileInfo.fileNames = StreamSupport.stream(files.spliterator(), false)
                        .map(JsonNode::asText)
                        .collect(Collectors.toList());
            }
        }
        return fileInfo;
    }

    private static class FileInfo {
        String directory = "";
        List<String> fileNames = Collections.emptyList();
    }

    private static boolean isSuccess(String operateState) {
        return "success".equalsIgnoreCase(
                operateState != null ? operateState.trim() : ""
        );
    }

}